// STD
#include <iostream>
#include <string>
#include <sstream>
#include <fstream>

// QT
#include <QDebug>

// PROJECT
#include "cmesh.h"
#include "tools.h"



CMesh::CMesh()
{
    this->clearAllList();
    this->m_bVerticesNormals = false;
    this->m_bBuilt = false;
    this->m_pBS = NULL;
    this->m_pBB = NULL;
}

CMesh::~CMesh()
{
    for (unsigned i = 0; i < this->m_vVertexList.size(); ++i)
    {
        CVertex * pV = this->m_vVertexList.at(i);
        delete pV;
    }
    for (unsigned i = 0; i < this->m_vEdgeList.size(); ++i)
    {
        CEdge * pE = this->m_vEdgeList.at(i);
        delete pE;
    }
    for (unsigned i = 0; i < this->m_vFaceList.size(); ++i)
    {
        CFace * pF = this->m_vFaceList.at(i);
        delete pF;
    }
    this->clearAllList();
    delete this->m_pBS;
    delete this->m_pBB;
}

bool CMesh::LoadOBJ(std::string sFileName)
{
    return this->LoadOBJ(sFileName.c_str());
}

bool CMesh::LoadOBJ(const char * FileName)
{
    if (!this->m_vVertexList.empty() || !this->m_vEdgeList.empty() || !this->m_vFaceList.empty())
        this->clearAllList();

    FILE *pFile = fopen(FileName, "r");

    if (!pFile)
        return false;
    std::vector<CPoint3f> vNormal;
    std::vector<CVertex*> vVertices;
    std::vector<CEdge*>	  vEdges;
    std::vector<CFace*>   vFaces;

    int v[3] = {-1};
    int vt[3] = {-1};
    int vn[3] = {-1};
    char buffer[256] = {0};

    v[0]  = v[1]  = v[2]  = -1;
    vt[0] = vt[1] = vt[2] = -1;
    vn[0] = vn[1] = vn[2] = -1;

    double d1, d2, d3;

    bool bProblem = false;

    while (fscanf(pFile, "%s", buffer) != EOF && ! bProblem)
    {
        d1 = d2 = d3 = 10.0;
        switch (buffer[0])
        {
        case 'f': // v, v//vn, v/vt, or v/vt/vn.
            v[0]  = v[1]  = v[2]  = -1;
            vt[0] = vt[1] = vt[2] = -1;
            vn[0] = vn[1] = vn[2] = -1;

            fscanf(pFile, "%s", buffer);

            if (strstr(buffer, "//")) // v//vn
            {
                sscanf(buffer, "%d//%d", &v[0], &vn[0]);
                fscanf(pFile, "%d//%d", &v[1], &vn[1]);
                fscanf(pFile, "%d//%d", &v[2], &vn[2]);

                CFace * pFace = new CFace(this);
                vFaces.push_back(pFace);

                CVertex * pV1 = vVertices.at(v[0]-1);
                CVertex * pV2 = vVertices.at(v[1]-1);
                CVertex * pV3 = vVertices.at(v[2]-1);

                pFace->setVertex1(pV1);
                pFace->setVertex2(pV2);
                pFace->setVertex3(pV3);
                pFace->computeEdges();
                vEdges.push_back(pFace->getEdge1());
                vEdges.push_back(pFace->getEdge2());
                vEdges.push_back(pFace->getEdge3());
                pV1->addFace(pFace);
                pV2->addFace(pFace);
                pV3->addFace(pFace);
                pV1->setNormal(vNormal.at(vn[0]-1));
                pV1->setNormal(vNormal.at(vn[1]-1));
                pV1->setNormal(vNormal.at(vn[2]-1));
            }
            else if (sscanf(buffer, "%d/%d/%d", &v[0], &vt[0], &vn[0]) == 3) // v/vt/vn
            {
                fscanf(pFile, "%d/%d/%d", &v[1], &vt[1], &vn[1]);
                fscanf(pFile, "%d/%d/%d", &v[2], &vt[2], &vn[2]);

                CFace * pFace = new CFace(this);
                vFaces.push_back(pFace);
                CVertex * pV1 = vVertices.at(v[0]-1);
                CVertex * pV2 = vVertices.at(v[1]-1);
                CVertex * pV3 = vVertices.at(v[2]-1);

                pFace->setVertex1(pV1);
                pFace->setVertex2(pV2);
                pFace->setVertex3(pV3);
                pFace->computeEdges();
                vEdges.push_back(pFace->getEdge1());
                vEdges.push_back(pFace->getEdge2());
                vEdges.push_back(pFace->getEdge3());
                pV1->addFace(pFace);
                pV2->addFace(pFace);
                pV3->addFace(pFace);
                pV1->setNormal(vNormal.at(vn[0]-1));
                pV1->setNormal(vNormal.at(vn[1]-1));
                pV1->setNormal(vNormal.at(vn[2]-1));
            }
            else if (sscanf(buffer, "%d/%d", &v[0], &vt[0]) == 2) // v/vt
            {
                fscanf(pFile, "%d/%d", &v[1], &vt[1]);
                fscanf(pFile, "%d/%d", &v[2], &vt[2]);

                CFace * pFace = new CFace(this);
                vFaces.push_back(pFace);
                CVertex * pV1 = vVertices.at(v[0]-1);
                CVertex * pV2 = vVertices.at(v[1]-1);
                CVertex * pV3 = vVertices.at(v[2]-1);

                pFace->setVertex1(pV1);
                pFace->setVertex2(pV2);
                pFace->setVertex3(pV3);
                pFace->computeEdges();
                vEdges.push_back(pFace->getEdge1());
                vEdges.push_back(pFace->getEdge2());
                vEdges.push_back(pFace->getEdge3());
                pV1->addFace(pFace);
                pV2->addFace(pFace);
                pV3->addFace(pFace);
            }
            else
            if (sscanf(buffer, "%d", &v[0]) == 1) // v
            {
                fscanf(pFile, "%d", &v[1]);
                fscanf(pFile, "%d", &v[2]);

                CFace * pFace = new CFace(this);
                vFaces.push_back(pFace);
                CVertex * pV1 = vVertices.at(v[0]-1);
                CVertex * pV2 = vVertices.at(v[1]-1);
                CVertex * pV3 = vVertices.at(v[2]-1);

                pFace->setVertex1(pV1);
                pFace->setVertex2(pV2);
                pFace->setVertex3(pV3);
                pFace->computeEdges();
                vEdges.push_back(pFace->getEdge1());
                vEdges.push_back(pFace->getEdge2());
                vEdges.push_back(pFace->getEdge3());
                pV1->addFace(pFace);
                pV2->addFace(pFace);
                pV3->addFace(pFace);
            }
            else
            {
                bProblem = true;
                qDebug() << "\nMesh laoding: face with unknown caracteritics";
            }
            break;

        case 'v': // v, vn, or vt.
            switch (buffer[1])
            {
            case '\0': // v
                if (3 == fscanf(pFile, "%lf %lf %lf", &d1, &d2, &d3))
                {
                    vVertices.push_back(new CVertex(d1, d2, d3, this));
                }
                else
                {
                    bProblem = true;
                    qDebug() << "Mesh laoding: error reading vertex coordinates";
                }
                break;

            case 'n': // vn
                if (3 == fscanf(pFile, "%lf %lf %lf", &d1, &d2, &d3))
                {
                    vNormal.push_back(CPoint3f(d1, d2, d3));
                }
                else
                {
                    bProblem = true;
                    qDebug() << "Mesh laoding: error reading vertex's normal coordinates";
                }
                break;

            case 't': // vt
                if (2 == fscanf(pFile, "%lf %lf", &d1, &d2))
                {
                    qDebug() << "Mesh laoding: Reading vertex's textur coordinates";
                }
                else
                {
                    bProblem = true;
                    qDebug() << "Mesh laoding: error reading vertex's textur coordinates";
                }
                break;

            default:
                bProblem = true;
                qDebug() << "\nMesh laoding: unknown kind of v line";
                break;
            }
            break;

        case '#': // comment
            break;

        default:
            fgets(buffer, sizeof(buffer), pFile);
            break;
        }
    }

    fclose (pFile);

    if (!bProblem)
    {
        this->m_vVertexList = vVertices;
        this->m_vEdgeList = vEdges;
        this->m_vFaceList = vFaces;
        this->pairEdges();
        this->checkVerticesNormals();
        this->setupBoundingBox();
        this->setupBoundingSphere();
        this->m_bBuilt = true;
//            qDebug() << "\nMesh laoding: success - " << vFaces.size() << " faces.";
        return true;
    }

    qDebug() << "\nMesh laoding: failed\n";
    return false;
}

bool CMesh::SaveOBJ(std::string sFileName)
{
    return this->SaveOBJ(sFileName.c_str());
}

bool CMesh::SaveOBJ(char * FileName)
{
    std::fstream file;
    file.open(FileName,std::fstream::out);
    if (!file.is_open())
        return false;

    this->checkVerticesNormals();

    if (this->m_bVerticesNormals)
    {
        for (unsigned i = 0; i < this->m_vVertexList.size(); ++i)
        {
            CVertex* tempVertex = this->m_vVertexList.at(i);
            file << "v " << tempVertex->getPosition().GetX() << ' ' << tempVertex->getPosition().GetY() << ' ' << tempVertex->getPosition().GetZ() << '\n'
                 << "vn " << tempVertex->getNormal().GetX() << ' ' << tempVertex->getNormal().GetY() << ' ' << tempVertex->getNormal().GetZ() << '\n';
        }

        for (unsigned i = 0; i < this->m_vFaceList.size(); ++i)
        {
            CFace* tempFace = this->m_vFaceList.at(i);
            unsigned ind1 = this->findIndOfVertex(tempFace->getVertex1())+1;
            unsigned ind2 = this->findIndOfVertex(tempFace->getVertex2())+1;
            unsigned ind3 = this->findIndOfVertex(tempFace->getVertex3())+1;
            file << "f " << ind1 << "//" << ind1
                 << ' '  << ind2 << "//" << ind2
                 << ' '  << ind3 << "//" << ind3
                 << '\n';
        }
    }
    else
    {
        for (unsigned i = 0; i < this->m_vVertexList.size(); ++i)
        {
            CVertex* tempVertex = this->m_vVertexList.at(i);
            file << "v " << tempVertex->getPosition().GetX() << ' ' << tempVertex->getPosition().GetY() << ' ' << tempVertex->getPosition().GetZ() << '\n';
        }

        for (unsigned i = 0; i < this->m_vFaceList.size(); ++i)
        {
            CFace* tempFace = this->m_vFaceList.at(i);
            unsigned ind1 = this->findIndOfVertex(tempFace->getVertex1())+1;
            unsigned ind2 = this->findIndOfVertex(tempFace->getVertex2())+1;
            unsigned ind3 = this->findIndOfVertex(tempFace->getVertex3())+1;
            file << "f " << ind1
                 << ' '  << ind2
                 << ' '  << ind3
                 << '\n';
        }
    }
    file.close();
    qDebug() << "\nSauvegarde termin�e\n";
    return true;
}

void CMesh::clearVertexList()
{
    this->m_vVertexList.clear();
}

void CMesh::clearEdgeList()
{
    this->m_vEdgeList.clear();
}

void CMesh::clearFaceList()
{
    this->m_vFaceList.clear();
}

void CMesh::clearAllList()
{
    this->clearVertexList();
    this->clearEdgeList();
    this->clearFaceList();
    this->m_bBuilt = false;
}

int CMesh::findIndOfVertex(CVertex * pVertex)
{
    for (unsigned i = 0; i < this->m_vVertexList.size(); ++i)
    {
        if (pVertex == this->m_vVertexList.at(i))
        {
            return i;
        }
    }
    return -1;
}

bool CMesh::doesEdgeExist(CVertex * pV1, CVertex * pV2)
{
    CEdge * tempEdge;
    for (unsigned i = 0; i < this->m_vEdgeList.size(); ++i)
    {
        tempEdge = this->m_vEdgeList.at(i);
        if ((tempEdge->getHead() == pV1 && tempEdge->getTail() == pV2))
            return true;
    }
    return false;
}

CEdge * CMesh::getEdgeFromVertices(CVertex * pV1, CVertex * pV2)
{
    CEdge * tempEdge;
    for (unsigned i = 0; i < this->m_vEdgeList.size(); ++i)
    {
        tempEdge = this->m_vEdgeList.at(i);
        if ((tempEdge->getHead() == pV1 && tempEdge->getTail() == pV2))
            return tempEdge;
    }
    return NULL;
}


CVertex * CMesh::getVertexByPos(CPoint3f P)
{
    CVertex * Res = NULL;

    for (unsigned i = 0; i < this->m_vVertexList.size() && !Res; ++i)
    {
        CVertex * temp = this->m_vVertexList.at(i);
        if (temp->getPosition()== P)
            Res = temp;
    }

    return Res;
}

void CMesh::checkVerticesNormals()
{
    bool found = true;
    for (unsigned i = 0; i < this->m_vVertexList.size() && found; ++i)
    {
        CVertex * pV = this->m_vVertexList.at(i);
        if (pV->isNormalSet())
            found = false;
    }
    if (found)
        this->m_bVerticesNormals = true;
    else
        this->computeNormals();
}

void CMesh::normalizeSize()
{
    CPoint3f * pCenter = new CPoint3f();
    for (unsigned i= 0; i < this->m_vVertexList.size(); ++i)
    {
        pCenter->Add(((CVertex*)(this->m_vVertexList.at(i)))->getPosition());
    }

    unsigned uNb = this->m_vVertexList.size();
    pCenter->SetX(pCenter->GetX()/(float)uNb);
    pCenter->SetY(pCenter->GetY()/(float)uNb);
    pCenter->SetZ(pCenter->GetZ()/(float)uNb);

    double fMax = 0.0;
    for (unsigned i= 0; i < this->m_vVertexList.size(); ++i)
    {
        CVertex * pVTemp = this->m_vVertexList.at(i);
        float fTemp = pCenter->Distance(pVTemp->getPosition());
        if (fTemp > fMax)
            fMax = fTemp;
    }

    if (pCenter->GetX() != 0.0 || pCenter->GetY() != 0.0 || pCenter->GetZ() != 0.0)
    {
        for (unsigned i= 0; i < this->m_vVertexList.size(); ++i)
        {
            CVertex * pVTemp = this->m_vVertexList.at(i);
            pVTemp->setX(pVTemp->getX()-pCenter->GetX());
            pVTemp->setY(pVTemp->getY()-pCenter->GetY());
            pVTemp->setZ(pVTemp->getZ()-pCenter->GetZ());
        }
    }

    for (unsigned i= 0; i < this->m_vVertexList.size(); ++i)
    {
        CVertex * pVTemp = this->m_vVertexList.at(i);
        pVTemp->setPosition(pVTemp->getX()/fMax, pVTemp->getY()/fMax, pVTemp->getZ()/fMax);
    }
}

void CMesh::computeNormals()
{
    for (unsigned i = 0; i < this->m_vVertexList.size(); ++i)
    {
        CVertex * pVertex = this->m_vVertexList.at(i);
        pVertex->computeNormal();
    }
    this->m_bVerticesNormals = true;
}

void CMesh::computeEdges()
{
    this->clearEdgeList();
    for (unsigned i = 0; i < this->m_vFaceList.size(); ++i)
    {
        CFace * pFace = this->m_vFaceList.at(i);

        pFace->computeEdges();
        this->m_vEdgeList.push_back(pFace->getEdge1());
        this->m_vEdgeList.push_back(pFace->getEdge2());
        this->m_vEdgeList.push_back(pFace->getEdge3());
    }
    this->pairEdges();
}

void CMesh::pairEdges()
{
    for (unsigned i = 0; i < this->m_vEdgeList.size(); ++i)
    {
        CEdge * pE = this->m_vEdgeList.at(i);
        pE->setTwinEdge(this->getEdgeFromVertices(pE->getTail(), pE->getHead()));
    }
}

void CMesh::makeCopyOf(CMesh * pMesh)
{
    this->clearAllList();
    this->m_bVerticesNormals = pMesh->m_bVerticesNormals;
    this->m_bBuilt = pMesh->m_bBuilt;

    for (unsigned i = 0; i < pMesh->m_vVertexList.size(); ++i)
    {
        CVertex * pVorigin = pMesh->m_vVertexList.at(i);
        CVertex * pV = new CVertex(pVorigin->getX(), pVorigin->getY(), pVorigin->getZ(), pVorigin->getParentMesh());
        if (pVorigin->isNormalSet())
            pV->setNormal(pVorigin->getNormal());
        this->m_vVertexList.push_back(pV);
    }

    for (unsigned i = 0; i < pMesh->m_vFaceList.size(); ++i)
    {
        CFace * pForigin = pMesh->m_vFaceList.at(i);
        CFace * pFace = new CFace(pForigin->getParentMesh());

        CVertex * pV1 = this->m_vVertexList.at(pMesh->findIndOfVertex(pForigin->getVertex1()));
        CVertex * pV2 = this->m_vVertexList.at(pMesh->findIndOfVertex(pForigin->getVertex2()));
        CVertex * pV3 = this->m_vVertexList.at(pMesh->findIndOfVertex(pForigin->getVertex3()));
        pFace->setVertex1(pV1);
        pFace->setVertex2(pV2);
        pFace->setVertex3(pV3);
        pV1->addFace(pFace);
        pV2->addFace(pFace);
        pV3->addFace(pFace);
        this->m_vFaceList.push_back(pFace);
    }

    this->computeEdges();
}

bool CMesh::isBuilt()
{
    return m_bBuilt;
}

void CMesh::setMaterial(CMaterial mat)
{
    this->m_Material = mat;
}


void CMesh::paint()
{
    glColor3f(this->m_Material.m_fRed, this->m_Material.m_fGreen, this->m_Material.m_fBlue);
    for (unsigned i = 0; i < this->m_vFaceList.size(); ++i)
    {
        CFace * pFace = this->m_vFaceList.at(i);
        glBegin(GL_TRIANGLES);
            glNormal3f(pFace->getNormal().GetX(),pFace->getNormal().GetY(),pFace->getNormal().GetZ());
            glVertex3f(pFace->getVertex1()->getX(),pFace->getVertex1()->getY(),pFace->getVertex1()->getZ());

            glNormal3f(pFace->getNormal().GetX(),pFace->getNormal().GetY(),pFace->getNormal().GetZ());
            glVertex3f(pFace->getVertex2()->getX(),pFace->getVertex2()->getY(),pFace->getVertex2()->getZ());

            glNormal3f(pFace->getNormal().GetX(),pFace->getNormal().GetY(),pFace->getNormal().GetZ());
            glVertex3f(pFace->getVertex3()->getX(),pFace->getVertex3()->getY(),pFace->getVertex3()->getZ());
        glEnd();
    }
}

void CMesh::setupBoundingSphere()
{
    float sX = 0;
    float sY = 0;
    float sZ = 0;

    for (unsigned i= 0; i < this->m_vVertexList.size(); ++i)
    {
        CVertex * pVTemp = this->m_vVertexList.at(i);
        sX += pVTemp->getX();
        sY += pVTemp->getY();
        sZ += pVTemp->getZ();
    }

    CPoint3f BCentre (sX/this->m_vVertexList.size(),sY/this->m_vVertexList.size(),sZ/this->m_vVertexList.size());

    double radiusMin = 0;
    for (unsigned i= 0; i < this->m_vVertexList.size(); ++i)
    {
        CVertex * pVTemp = this->m_vVertexList.at(i);
        if(pVTemp->getPosition().Distance2(BCentre) > radiusMin)
            radiusMin = pVTemp->getPosition().Distance2(BCentre);
    }
    this->m_pBS = new CBoundingSphere(this, CPoint3f(BCentre.GetX(),BCentre.GetY(),BCentre.GetZ()),sqrt(radiusMin));
    for (unsigned i = 0; i < this->m_vFaceList.size(); ++i)
    {
        CFace * pFace = this->m_vFaceList.at(i);
        pFace->setupBB();
    }
}

void CMesh::setupBoundingBox()
{
    double fXMin = std::numeric_limits<double>::max(),
           fXMax = std::numeric_limits<double>::min(),
           fYMin = std::numeric_limits<double>::max(),
           fYMax = std::numeric_limits<double>::min(),
           fZMin = std::numeric_limits<double>::max(),
           fZMax = std::numeric_limits<double>::min();

    for (unsigned i = 0; i < this->m_vFaceList.size(); ++i)
    {
        CPoint3f PMin, PMax;
        CFace* pFace = this->m_vFaceList.at(i);
        pFace->setupBB();
        pFace->m_pBB->getBoundingBox(PMin, PMax);
        fXMin = min(fXMin, PMin.GetX());
        fXMax = max(fXMax, PMax.GetX());
        fYMin = min(fYMin, PMin.GetY());
        fYMax = max(fYMax, PMax.GetY());
        fZMin = min(fZMin, PMin.GetZ());
        fZMax = max(fZMax, PMax.GetZ());
    }
    if (this->m_pBB)
        delete this->m_pBB;
    this->m_pBB = new CBoundingBox(this, CPoint3f(fXMin,fYMin,fZMin), CPoint3f(fXMax,fYMax,fZMax));
}

std::string CMesh::className()
{
    return std::string("CMesh");
}

CPoint3f V2P(CVector3f V)
{
    return CPoint3f(V.m_fX,V.m_fY,V.m_fZ);
}

CVector3f P2V(CPoint3f P)
{
    return CVector3f(P.GetX(),P.GetY(),P.GetZ());
}


bool CMesh::intersect(CRay * pRay, CPoint3f & P, CVector3f & V)
{
    bool retvalue = true;
    bool retvalueFinal = false;
    CPoint3f interTmp;

    if (this->m_pBB)
        if(!this->m_pBB->intersect(pRay))
            return false;

    if (this->m_pBS)
        if (!this->m_pBS->intersect(pRay))
            return false;

    for (unsigned i = 0; i < this->m_vFaceList.size(); ++i)
    {
        retvalue = true;
        CFace * pFace = this->m_vFaceList.at(i);
        if(pFace->m_pBB->intersect(pRay))
        {
            CVector3f p1(pFace->getVertex1()->getX(),pFace->getVertex1()->getY(),pFace->getVertex1()->getZ());
            CVector3f p2(pFace->getVertex2()->getX(),pFace->getVertex2()->getY(),pFace->getVertex2()->getZ());
            CVector3f p3(pFace->getVertex3()->getX(),pFace->getVertex3()->getY(),pFace->getVertex3()->getZ());

            CVector3f    u, v, n;
            CVector3f    dir, w0, w;
            float         r, a, b;
            u = p2 - p1;
            v = p3 - p1;
            n = v.crossProduct(u);

            dir = pRay->m_Direction;

            w0 = P2V(pRay->m_Start) - p1;

            a = -((n).m_fX * (w0).m_fX + (n).m_fY * (w0).m_fY + (n).m_fZ * (w0).m_fZ);
            b =  ((n).m_fX * (dir).m_fX + (n).m_fY * (dir).m_fY + (n).m_fZ * (dir).m_fZ);

            if (fabs(b) < 0.0001)
                retvalue = false;
            if(retvalue)
            {
                r = a / b;
                if (r < 0.0)
                    retvalue = false;

                if(retvalue)
                {
                    CVector3f tmp = dir * r;
                    CVector3f tmp2 = P2V(pRay->m_Start);
                    CVector3f tmp3 = tmp2 + tmp;
                    interTmp = CPoint3f(V2P(tmp3));

                    float    uu, uv, vv, wu, wv, D;

                    uu = ((u).m_fX * (u).m_fX + (u).m_fY * (u).m_fY + (u).m_fZ * (u).m_fZ);
                    uv = ((u).m_fX * (v).m_fX + (u).m_fY * (v).m_fY + (u).m_fZ * (v).m_fZ);
                    vv = ((v).m_fX * (v).m_fX + (v).m_fY * (v).m_fY + (v).m_fZ * (v).m_fZ);
                    w = P2V(interTmp) - p1;
                    wu = ((w).m_fX * (u).m_fX + (w).m_fY * (u).m_fY + (w).m_fZ * (u).m_fZ);
                    wv = ((w).m_fX * (v).m_fX + (w).m_fY * (v).m_fY + (w).m_fZ * (v).m_fZ);
                    D = uv * uv - uu * vv;

                    float s, t;
                    s = (uv * wv - vv * wu) / D;
                    if (s < 0.0 || s > 1.0)
                        retvalue = false;
                    t = (uv * wu - uu * wv) / D;
                    if (t < 0.0 || (s + t) > 1.0)
                        retvalue = false;


                    if (retvalue && !retvalueFinal)
                    {
                        CVector3f vTmp = CVector3f(pFace->getNormal().GetX(),pFace->getNormal().GetY(),pFace->getNormal().GetZ());
                        if(pRay->m_Start.Distance(interTmp)>0.1f)
                        {
                            pFace->computeNormal();
                            V = CVector3f(pFace->getNormal().GetX(),pFace->getNormal().GetY(),pFace->getNormal().GetZ());
                            P = interTmp;
                            V = vTmp;
                            retvalueFinal = true;
                        }
                    }

                    if (retvalue && retvalueFinal)
                    {
                        CVector3f vTmp = CVector3f(pFace->getNormal().GetX(),pFace->getNormal().GetY(),pFace->getNormal().GetZ());
                        if(pRay->m_Start.Distance(interTmp)>0.1f)
                        {
                            if(interTmp.Distance(pRay->m_Start)<P.Distance(pRay->m_Start))
                            {
                                pFace->computeNormal();
                                V = vTmp;
                                P = interTmp;
                                retvalue  = true;
                            }
                        }
                    }
                }
            }
        }
    }
    return retvalueFinal;
}
